#pragma once

#include <d3d9.h>
#include <time.h>
#include <d3dx9.h>
#include <windows.h>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cmath>


LPDIRECT3DSURFACE9 CreateSurfaceFromFile(LPDIRECT3DDEVICE9 d3ddv, LPWSTR FilePath);

enum BridgeState
{
	STATE_Assign = 1,
	STATE_Fire = 0,
	STATE_End = -1
};

enum EffectType
{
	TYPE_Bridge_Fier = 0,
	TYPE_Object_Burning = 1,
	TYPE_Object_Fire = 2,
	TYPE_Bullet_Small_Fire = 3,
	TYPE_Bullet_Big_Fire = 4,
	TYPE_Water_Fall = 5
};

enum ItemBlockStates {
	StateBlock = 1, 
	StateFired = 2,
	StateBlockClose = 3,
	StateBlockClosing = 4,
	StateBlockOpen = 5,
	StateBlockOpening = 6
};

enum GameLevels
{
	GameLevel1 = 1,
	GameLevel2 = 2,
	GameLevel3 = 3,
	GameLevel1Sprite = 4,
	GameLevel2Sprite = 5,
	GameLevel3Sprite = 6
};

enum BulletArmies {
	BulletPlayer = 0,
	BulletArmy = 1
};

struct cmp_str
{
	bool operator()(char const *a, char const *b)
	{
		return strcmp(a, b) < 0;
	}
};

enum ActionType
{
	ActionAttack = 0,
	ActionBonus = 1
};

struct ActionInfo{
	int damage;
	ActionType action;
	ActionInfo(int damage, ActionType action)
	{
		this->action = action;
		this->damage = damage;
	}
};

struct Rect {
	double X, Y, Vx, Vy;
	int Width, Height;

	double getLeft() { return X - Width / 2; }
	double getRight() { return X + Width / 2; }
	double getTop() { return Y + Height / 2; }
	double getBottom() { return Y - Height / 2; }

	void setPosition(double x, double y) {
		X = x;
		Y = y;
	}

	Rect() {}
	bool IsIntersectOne(Rect* rectA, Rect* rectB) { // clipping check
		int left, right, top, bottom;

		left = rectA->getLeft() < rectB->getLeft() ? rectB->getLeft() : rectA->getLeft();
		right = rectA->getRight() < rectB->getRight() ? rectA->getRight() : rectB->getRight();
		top = rectA->getTop() < rectB->getTop() ? rectA->getTop() : rectB->getTop();
		bottom = rectA->getBottom() < rectB->getBottom() ? rectB->getBottom() : rectA->getBottom();

		if (left < right && top > bottom) // >
			return true;
		else 
			return false;
	}

	bool IsIntersectAll(Rect* rectA, Rect *rectB) {
		return IsIntersectOne(rectA, rectB);//IsIntersectOne(rectA, rectB) || IsIntersectOne(rectB, rectA);
	}

	// without movement (Vx, Vy)
	bool checkAABB(Rect* rectA, Rect* rectB)
	{
		return !(rectA->getRight() < rectB->getLeft() ||
			rectA->getLeft() > rectB->getRight() ||
			rectA->getBottom() < rectB->getTop() ||
			rectA->getTop() > rectB->getBottom());
	}

	// with reponse 
	bool checkAABB(Rect* rectA, Rect* rectB, double &movex, double &movey)
	{
		movex = movey = 0.0f;
		float left, right, bottom, top;
		left = rectB->getLeft() - (rectA->getRight());
		right = (rectB->getRight()) - rectA->getLeft();
		bottom = (rectB->getBottom()) - rectA->getTop();
		top = (rectB->getTop()) - (rectA->getBottom());

		// check collision
		if (left > 0 || right < 0 || top > 0 || bottom < 0)
			return false;

		movex = abs(left) < right ? left : right;
		movey = abs(top) < bottom ? top : bottom;
		
		if (abs(movex) < abs(movey))
			movey = 0.0f;
		else
			movex = 0.0f;
		return true;
	}

	Rect(double x, double y, int height, int width) {
		X = x; Y = y;
		Vx = Vy = 0;
		Height = height; Width = width;
	}

	float sweptAABB(Rect* rectA, Rect* rectB, float &normalx, float &normaly)
	{
		if (IsIntersectAll(rectA, rectB)) {
			return 0.0f;
		}

		float xInvEntry, yInvEntry;
		float xInvExit, yInvExit;
		float Vx, Vy;
		rectA->Vx == 0.0f ? Vx = 0.1f : Vx = rectA->Vx;
		rectA->Vy == 0.0f ? Vy = 0.1f : Vy = rectA->Vy;

		// find the distance between the objects on the near and far sides for both x and y
		if (Vx > 0.0f)
		{
			xInvEntry = rectB->getLeft() - rectA->getRight();
			xInvExit = rectB->getRight() - rectA->getLeft();
		}
		else
		{
			xInvEntry = rectB->getRight() - rectA->getLeft();
			xInvExit = rectB->getLeft() - rectA->getRight();
		}

		if (Vy < 0.0f)
		{
			yInvEntry = rectB->getTop() - rectA->getBottom();
			yInvExit = rectB->getBottom() - rectA->getTop();
		}
		else
		{
			yInvEntry = rectB->getBottom() - rectA->getTop();
			yInvExit = rectB->getTop() - rectA->getBottom();
		}

		// find time of collision and time of leaving for each axis (if statement is to prevent divide by zero)
		float xEntry, yEntry;
		float xExit, yExit;

		if (Vx == 0.0f)
		{
			xEntry = -std::numeric_limits<float>::infinity();
			xExit = std::numeric_limits<float>::infinity();
		}
		else
		{
			xEntry = xInvEntry / Vx;
			xExit = xInvExit / Vx;
		}

		if (Vy == 0.0f)
		{
			yEntry = -std::numeric_limits<float>::infinity();
			yExit = std::numeric_limits<float>::infinity();
		}
		else
		{
			yEntry = yInvEntry / Vy;
			yExit = yInvExit / Vy;
		}

		// find the earliest/latest times of collision
		float entryTime = max(xEntry, yEntry);
		float exitTime = min(xExit, yExit);

		// if there was no collision
		if (entryTime >= exitTime || xEntry < 0 && yEntry < 0 || xEntry > 1.0f || yEntry > 1.0f || (rectA->X < rectB->getLeft() - 10) || (rectA->X > rectB->getRight() + 10))
		{
			normalx = 0.0f;
			normaly = 0.0f;
			return 1.0f;
		}
		else // if there was a collision
		{
			// calculate normal of collided surface
			if (xEntry > yEntry)
			{
				if (xInvEntry < 0.0f)
				{
					normalx = 1.0f;
					normaly = 0.0f;
				}
				else
				{
					normalx = -1.0f;
					normaly = 0.0f;
				}
			}
			else
			{
				if (yInvEntry < 0.0f)
				{
					normalx = 0.0f;
					normaly = 1.0f;
				}
				else
				{
					normalx = 0.0f;
					normaly = -1.0f;
				}
			}

			// return the time of collision
			return entryTime;
		}
	}
};

enum ACTIONS {
	ACTIONS_STOP_FLYING = 1,
	ACTIONS_JUMPING = 2,
    ACTIONS_IN_WATER = 3,
	ACTIONS_IS_HURT = 4,
	ACTIONS_HIT_PLAYER = 5,
	ACTIONS_HIT_ITEM = 6,
	ACTIONS_KILL_BULLET = 7,
	ACTIONS_NONE = 100,
	ACTIONS_STONE_IN_LAND = 8,
	ACTIONS_BOOM_KILL = 9,
	ACTIONS_BOSS3_ITEM_IN_LAND = 10,
	ACTIONS_BOSS1_ENEMY_HURT = 11
};

